//! @file   lc_linked_list_impl.h
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#ifndef _LC_LINKED_LIST_H
#   error "Include <lc_linked_list.h> instead!"
#endif /* _LC_LINKED_LIST_H */

namespace cyan {
  namespace internal {        
    template <typename T>
    void ListBase<T>::clear() {
      ListNode<T>* current = static_cast<ListNode<T>*>(this->node_.next);

      while (current != &this->node_) {
        ListNode<T>* temp = current;
        current = static_cast<ListNode<T>*>(current->next);
        temp->data.~T();
        this->putNode(temp);
      }
    }
  }

  template <typename T>
  typename LinkedList<T>::Iterator
  LinkedList<T>::insert(Iterator position, ConstReference value) {
    Node* node = LinkedList::createNode(value);
    node->hook(position.node);
    return Iterator(node);
  }

  template <typename T>
  typename LinkedList<T>::Iterator
  LinkedList<T>::erase(Iterator position) {
    Iterator next = Iterator(position.node->next);
    this->eraseHelper(position.node);
    return next;
  }

  template <typename T>
  void
  LinkedList<T>::splice(Iterator position, Iterator first, Iterator last) {
    if (first != last) {
      this->transfer(position, first, last);
    }
  }

  template <typename T>
  void
  LinkedList<T>::splice(Iterator position, LinkedList& otherList) {
    if (!otherList.isEmpty()) {
      this->transfer(position, otherList.begin(), otherList.end());
    }
  }

  template <typename T>
  LinkedList<T>&
  LinkedList<T>::operator =(const LinkedList& otherList) {
    if (this != &otherList) {
      Iterator first1 = this->begin();
      Iterator last1 = this->end();
      ConstIterator first2 = otherList.begin();
      ConstIterator last2 = otherList.end();

      for (; first1 != last1 && first2 != last2; ++first1, ++first2)
        *first1 = *first2;

      if (first1 != last1) {
        this->erase(first1, last1);
      } else {
        this->insert(first1, first2, last2);
      }
    }
    return *this;
  }

  template <typename T>
  void
  LinkedList<T>::unique() {
    Iterator first = this->begin();
    Iterator last = this->end();

    if (first == last)
      return;

    Iterator next = first;
    while (++next != last) {
      if (*first == *next)
        this->erase_(next);
      else
        first = next;
      next = first;
    }
  }

  template <typename T>
  template <typename BinaryPredicate>
  void
  LinkedList<T>::unique(BinaryPredicate predicate) {
    Iterator first = this->begin();
    Iterator last = this->end();

    if (first == last)
      return;

    Iterator next = first;
    while (++next != last) {
      if (predicate(*first, *next))
        this->erase(next);
      else
        first = next;
      next = first;
    }
  }

  template <typename T>
  template <typename UnaryPredicate>
  void
  LinkedList<T>::removeIf(UnaryPredicate predicate) {
    Iterator first = this->begin();
    Iterator last = this->end();

    while (first != last) {
      Iterator next = first;
      ++next;
      if (predicate(*first))
        this->eraseHelper(first);
      first = next;
    }
  }

  template <typename T>
  void
  LinkedList<T>::remove(ConstReference value) {
    Iterator first = this->begin();
    Iterator last = this->end();

    while (first != last) {
      Iterator next = first;
      ++next;
      if (*first == value)
        this->eraseHelper(first);
      first = next;
    }
  }
}
